#include"helper.h"
#ifdef _ICONV_SUPPORT

int CharsetConvert(LPCSTR lpszFromCharset, LPCSTR lpszToCharset, LPCSTR lpszInBuf, int iInBufLen, LPSTR lpszOutBuf, int& iOutBufLen)
{
	ASSERT(lpszInBuf != nullptr);

	SIZE_T nInBufLeft = iInBufLen;
	SIZE_T nOutBufLeft = iOutBufLen;
	int iOutBufSize = iOutBufLen;
	iOutBufLen = 0;

	if (lpszInBuf == nullptr)
	{
		//SetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
	}

	iconv_t ic = iconv_open(lpszToCharset, lpszFromCharset);

	if ((void*)-1 == ic)
		return FALSE;

	SIZE_T rs = iconv(ic, (LPSTR*)&lpszInBuf, &nInBufLeft, &lpszOutBuf, &nOutBufLeft);
	iOutBufLen = iOutBufSize - (int)nOutBufLeft;

	iconv_close(ic);

	return !(rs ==-1);
}

int GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
{
	int iInBufLen = (szSrc != nullptr) ? (int)strlen(szSrc) + 1 : 0;
	if (szDest==NULL||iDestLength==0)
	{
		iDestLength = iInBufLen ;
		return FALSE;
	}
	int iOutBufLen = (int)(iDestLength * sizeof(wchar_t));

	BOOL isOK = CharsetConvert(CHARSET_GBK, CHARSET_UTF_32LE, szSrc, iInBufLen, (char*)szDest, iOutBufLen);
	iDestLength = (int)(iOutBufLen / sizeof(wchar_t));

	return isOK;
}

int UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
{
	int iInBufLen = (szSrc != nullptr) ? (int)((wcslen(szSrc) + 1) * sizeof(wchar_t)) : 0;

	return CharsetConvert(CHARSET_UTF_32LE, CHARSET_GBK, (LPCSTR)szSrc, iInBufLen, szDest, iDestLength);
}

int Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
{
	int iInBufLen = (szSrc != nullptr) ? (int)strlen(szSrc) + 1 : 0;
	int iOutBufLen = (int)(iDestLength * sizeof(wchar_t));

	BOOL isOK = CharsetConvert(CHARSET_UTF_8, CHARSET_UTF_32LE, szSrc, iInBufLen, (char*)szDest, iOutBufLen);
	iDestLength = (int)(iOutBufLen / sizeof(wchar_t));

	return isOK;
}

int UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
{
	int iInBufLen = (szSrc != nullptr) ? (int)((wcslen(szSrc) + 1) * sizeof(wchar_t)) : 0;
	if (iDestLength==0|| szDest == NULL)
	{
		iDestLength = iInBufLen * 2;
		return FALSE;
	}

	return CharsetConvert(CHARSET_UTF_32LE, CHARSET_UTF_8, (LPCSTR)szSrc, iInBufLen, szDest, iDestLength);
}

int GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
{
	int iInBufLen = (szSrc != nullptr) ? (int)strlen(szSrc) + 1 : 0;
	

	return CharsetConvert(CHARSET_GBK, CHARSET_UTF_8, szSrc, iInBufLen, szDest, iDestLength);
}

int Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
{
	int iInBufLen = (szSrc != nullptr) ? (int)strlen(szSrc) + 1 : 0;
	
	return CharsetConvert(CHARSET_UTF_8, CHARSET_GBK, szSrc, iInBufLen, szDest, iDestLength);
}

#else




int CodePageToUnicode(int iCodePage, const char szSrc[], wchar_t szDest[], int& iDestLength)
{
	assert(szSrc);

	int iSize = ::MultiByteToWideChar(iCodePage, 0, szSrc, -1, nullptr, 0);

	if (iSize == 0 || iSize > iDestLength || !szDest || iDestLength == 0)
	{
		iDestLength = iSize;
		return FALSE;
	}

	if (::MultiByteToWideChar(iCodePage, 0, szSrc, -1, szDest, iSize) != 0)
		iDestLength = iSize;
	else
		iDestLength = 0;

	return iDestLength != 0;
}

int UnicodeToCodePage(int iCodePage, const WCHAR szSrc[], char szDest[], int& iDestLength)
{
	assert(szSrc);

	int iSize = ::WideCharToMultiByte(iCodePage, 0, szSrc, -1, nullptr, 0, nullptr, nullptr);

	if (iSize == 0 || iSize > iDestLength || !szDest || iDestLength == 0)
	{
		iDestLength = iSize;
		return 0;
	}

	if (::WideCharToMultiByte(iCodePage, 0, szSrc, -1, szDest, iSize, nullptr, nullptr) != 0)
		iDestLength = iSize;
	else
		iDestLength = 0;

	return iDestLength != 0;
}

int GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
{
	return CodePageToUnicode(CP_ACP, szSrc, szDest, iDestLength);
}

int UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
{
	return UnicodeToCodePage(CP_ACP, szSrc, szDest, iDestLength);
}

int Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
{
	return CodePageToUnicode(CP_UTF8, szSrc, szDest, iDestLength);
}

int UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
{
	return UnicodeToCodePage(CP_UTF8, szSrc, szDest, iDestLength);
}

int GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
{
	int iMiddleLength = 0;
	GbkToUnicode(szSrc, nullptr, iMiddleLength);

	if (iMiddleLength == 0)
	{
		iDestLength = 0;
		return FALSE;
	}

	unique_ptr<WCHAR[]> p(new WCHAR[iMiddleLength]);
	GbkToUnicode(szSrc, p.get(), iMiddleLength);

	return UnicodeToUtf8(p.get(), szDest, iDestLength);
}

int Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
{
	int iMiddleLength = 0;
	Utf8ToUnicode(szSrc, nullptr, iMiddleLength);

	if (iMiddleLength == 0)
	{
		iDestLength = 0;
		return FALSE;
	}

	unique_ptr<WCHAR[]> p(new WCHAR[iMiddleLength]);
	Utf8ToUnicode(szSrc, p.get(), iMiddleLength);

	return UnicodeToGbk(p.get(), szDest, iDestLength);
}
#endif
